package com.redis.lock;

import com.redis.annotation.CacheLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author lizhilong
 * @Date 2020/12/7 21:56
 */
@Component
@Slf4j
@Aspect
public class CacheLockInterceptor {

    @Resource
    private KeyGeneratorSelector keyGeneratorSelector;
    @Resource
    private LockType lockType;


    @Around("execution(public * *(..)) && @annotation(com.redis.annotation.CacheLock)")
    public Object interceptor(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        CacheLock lock = method.getAnnotation(CacheLock.class);
        if (StringUtils.isEmpty(lock.prefix())) {
            throw new RuntimeException("前缀不能为空");
        }
        Class<? extends KeyGenerator> aClass = lock.keyGenerator();
        KeyGenerator keyGenerator = keyGeneratorSelector.getKeyGenerator(aClass);
        if(null == keyGenerator){
            throw new IllegalStateException("key 生成方式为空");
        }
        final String lockKey = keyGenerator.getLockKey(pjp);
        log.info("redis lock key is {}", lockKey);
        RLock rLock = lockType.getLock(lock.fair(), lockKey);
        if (lock.lockTime() > 0) {
            try {
                boolean tryLock = rLock.tryLock(lock.waitTime(), lock.lockTime(), lock.timeUnit());
                if (!tryLock) {
                    throw new RuntimeException("获取锁超时，请稍候重试");
                }
                try {
                    return pjp.proceed();
                } catch (Throwable throwable) {
                    //可以定制异常处理
                    if (throwable instanceof RuntimeException) {
                        RuntimeException exception = (RuntimeException) throwable;
                        throw exception;
                    } else {
                        log.error("方法执行异常，错误信息：{}", throwable.getMessage());
                        throw new RuntimeException("SYSTEM ERROR");
                    }
                }
            } catch (Exception e) {
                if (e instanceof RuntimeException) {
                    RuntimeException exception = (RuntimeException) e;
                    throw exception;
                }else {
                    log.error("获取分布式锁失败，错误信息：{}", e.getMessage());
                    throw new IllegalStateException("SYSTEM ERROR");
                }
            } finally {
                if (rLock.isHeldByCurrentThread()) {
                    rLock.unlock();
                }
            }
        } else {
            try {
                boolean tryLock = rLock.tryLock();
                if (!tryLock) {
                    throw new RuntimeException("请勿重复请求");
                }
                try {
                    return pjp.proceed();
                } catch (Throwable throwable) {
                    //定制异常处理
                    if (throwable instanceof RuntimeException) {
                        RuntimeException exception = (RuntimeException) throwable;
                        throw exception;
                    } else {
                        log.error("方法执行异常，错误信息：{}", throwable.getMessage());
                        throw new RuntimeException("SYSTEM ERROR");
                    }
                }
            } finally {
                if (rLock.isHeldByCurrentThread()) {
                    rLock.unlock();
                }
            }
        }
    }

}
